home *** CD-ROM | disk | FTP | other *** search
/ Aminet 15 / Aminet 15 - Nov 1996.iso / Aminet / dev / lang / FPL_v147.lha / fpl / src / compile.c < prev    next >
C/C++ Source or Header  |  1996-05-16  |  44KB  |  1,510 lines

  1. /************************************************************************
  2.  *                 FREXX PROGRAMMING LANGUAGE                     *
  3.  ************************************************************************
  4.  
  5.  Compile.c
  6.  
  7.  Functions to support the compiled programs executions.
  8.  
  9.  ************************************************************************/
  10.  
  11. /************************************************************************
  12.  *                                                                      *
  13.  * fpl.library - A shared library interpreting script langauge.         *
  14.  * Copyright (C) 1992-1994 FrexxWare                                    *
  15.  * Author: Daniel Stenberg                                              *
  16.  *                                                                      *
  17.  * This program is free software; you may redistribute for non          *
  18.  * commercial purposes only. Commercial programs must have a written    *
  19.  * permission from the author to use FPL. FPL is *NOT* public domain!   *
  20.  * Any provided source code is only for reference and for assurance     *
  21.  * that users should be able to compile FPL on any operating system     *
  22.  * he/she wants to use it in!                                           *
  23.  *                                                                      *
  24.  * You may not change, resource, patch files or in any way reverse      *
  25.  * engineer anything in the FPL package.                                *
  26.  *                                                                      *
  27.  * This program is distributed in the hope that it will be useful,      *
  28.  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
  29.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                 *
  30.  *                                                                      *
  31.  * Daniel Stenberg                                                      *
  32.  * Ankdammsgatan 36, 4tr                                                *
  33.  * S-171 43 Solna                                                       *
  34.  * Sweden                                                               *
  35.  *                                                                      *
  36.  * FidoNet 2:201/328    email:dast@sth.frontec.se                       *
  37.  *                                                                      *
  38.  ************************************************************************/
  39.  
  40. #include "script.h"
  41. #include "compile.h"
  42. #include <stddef.h>
  43.  
  44. ReturnCode REGARGS
  45. FixVariable(struct Data *scr,
  46.             struct Identifier *ident,
  47.             long control,
  48.             struct Expr *expr);
  49. ReturnCode REGARGS FixFunction(struct Data *,
  50.                                struct Expr **,
  51.                                struct Expr *,
  52.                                Pass2,
  53.                                long);
  54. ReturnCode REGARGS
  55. CmpStringExpr(struct Expr *val,        /* original string -> new */
  56.          struct Data *scr);        /* standard */
  57.  
  58. ReturnCode REGARGS
  59. GetArrayNum(struct Data *,
  60.             struct Expr *,
  61.             long *,
  62.             struct Identifier *);
  63.  
  64. /************************************************************************
  65.  *
  66.  * IsCompiled()
  67.  *
  68.  * Returns the start-index if the program sent as parameter is compiled,
  69.  * or a negative value if not.
  70.  *
  71.  *********************************/
  72.  
  73. ReturnCode REGARGS SetupCompiled(struct Program *prog)
  74. {
  75.   uchar *original;
  76.   uchar *progpnt = prog->program;
  77.   if(!progpnt || memcmp(progpnt, COMPILED_HEADER, strlen(COMPILED_HEADER)))
  78.     return -1; /* not compiled, run as usual! */
  79.  
  80.   if(!(prog->flags&PR_COMPILED)) {
  81.     
  82.     original = progpnt; /* store where we start at! */
  83.   
  84.     /*
  85.      * Compiled programs contain at least this following header that
  86.      * we must pass in an elegant and forward compatible way!
  87.      * 'CODE' is the hunk we're after!
  88.      */
  89.     progpnt += COMPILED_HEADER_LEN; /* get to the first hunk */
  90.   
  91.     while(memcmp(progpnt, COMPILED_HUNK_CODE, strlen(COMPILED_HUNK_CODE))) {
  92.       /*
  93.        * As long as we haven't found the 'CODE' hunk, skip the unknown ones.
  94.        */
  95.       progpnt += COMPILED_HUNKNAME_LEN;
  96.       progpnt += *(long *)progpnt + COMPILED_HUNKLENGTH_LEN;
  97.     }
  98.     
  99.     progpnt += COMPILED_HUNKNAME_LEN + COMPILED_HUNKLENGTH_LEN;
  100.   
  101.     /*
  102.      * Set the information
  103.      */
  104.     
  105.     prog->flags |= PR_COMPILED;
  106.     prog->index = progpnt - original; /* index from start */
  107.     prog->startcol = prog->index;
  108.   }
  109.   return FPL_OK;
  110. }
  111.  
  112. /*
  113.  * CmpReset() - clears a local variable
  114.  */
  115.  
  116. ReturnCode REGARGS
  117. CmpReset(struct Data *scr,
  118.          long num)
  119. {
  120.   register long size=0;
  121.   long loop;
  122.   struct fplVariable *var = & scr->localinfo.list [ num ]->data.variable;
  123.   loop = var->size;
  124.   if( scr->localinfo.list [ num ]->flags & FPL_INT_VARIABLE) {
  125.     while(size < loop )
  126.       var->var.val32[ size++ ] = 0; /* reset to zero */
  127.   }
  128.   else {
  129.     while(size < loop ) {
  130.       if( var->var.str[ size ] ) {
  131.          /* The string has been set, make it zero length and zero
  132.             terminated */
  133.         var->var.str[ size ]->len = 0;
  134.         var->var.str[ size ]->string[0] = 0;
  135.       }
  136.       size++;
  137.     }
  138.   }
  139.   return FPL_OK;
  140. }
  141.  
  142. /*
  143.  * ReturnVariable() - returns the identifier pointer to the variable
  144.  */
  145. ReturnCode REGARGS
  146. ReturnVariable(struct Data *scr,
  147.                struct Identifier **ident,
  148.                long flags)
  149. {
  150.   struct Identifier *pident;
  151.  
  152.   GETMEM(pident, sizeof(struct Identifier));
  153.   memset(pident, 0, sizeof(struct Identifier));
  154.   pident->flags =flags;
  155.  
  156.   GETMEM(pident->data.variable.var.val32, sizeof(long));
  157.   *pident->data.variable.var.val32=0;
  158.   pident->data.variable.num=0;
  159.   pident->data.variable.size=1;
  160.   
  161.   *ident = pident;
  162.   return FPL_OK;
  163. }
  164.  
  165. /*
  166.  * CmpExport() - exports a specified function
  167.  */
  168. ReturnCode REGARGS CmpExport(struct Data *scr)
  169. {
  170.   struct Identifier *pident;
  171.   ReturnCode ret;
  172.  
  173.   GETMEM(pident, sizeof(struct Identifier));
  174.   memset(pident, 0, sizeof(struct Identifier));
  175.   pident->flags = GETLONG | FPL_COMPILER_ADDED;
  176.   P_LONG;
  177.   
  178.   /* start position index (add the actual index too) */
  179.   pident->data.inside.col = scr->prog->index + GETLONG;
  180.   P_LONG;
  181.   pident->data.inside.virfile = scr->virfile;
  182.   if( pident->flags & FPL_STRING_VARIABLE)
  183.     pident->data.inside.ret = FPL_STRARG;
  184.   else /* 'int' or 'void' kind */
  185.     pident->data.inside.ret = FPL_INTARG;
  186.  
  187.   /*
  188.    * Get name!
  189.    */
  190.   pident->name =
  191.     &scr->prog->program [ scr->prog->index + GETLONG + sizeof(long)];
  192.   P_LONG;
  193.  
  194.   /*
  195.    * Get parameter format!
  196.    */
  197.   pident->data.inside.format =
  198.     &scr->prog->program [ scr->prog->index + GETLONG + sizeof(long)];
  199.   P_LONG;
  200.  
  201.  
  202.   /*
  203.    * Setup the exported variable:
  204.    */
  205.   pident->data.inside.file = scr->prog->name;
  206.   pident->data.inside.virfile = scr->virfile;
  207.   pident->data.inside.prg = 1; /* always first line! */
  208.   
  209.   CALL(AddVar(scr, pident, &scr->globals ));
  210.  
  211.   return FPL_OK;
  212. }
  213.  
  214. /*
  215.  * CmpDeclare() - declares all kinds of variables
  216.  */
  217. ReturnCode REGARGS
  218. CmpDeclare(struct Data *scr)
  219. {
  220.   long flags;
  221.   long amount;
  222.   long firstid;
  223.   struct Identifier **temp;
  224.   struct Identifier *ident;
  225.   ReturnCode ret;
  226.   
  227.   flags   = GETLONG | FPL_COMPILER_ADDED;
  228.   firstid = *(long *)(scr->text+sizeof(long));
  229.  
  230.   if(!(flags&FPL_EXPORT_SYMBOL)) {
  231.     amount  = *(long *)(scr->text+sizeof(long)*2);
  232.     
  233.     scr->text += sizeof(long)*3; /* pass the three data longs */
  234.     
  235.     if(!(flags&FPL_GLOBAL_SYMBOL)) {
  236.       /* These are local ones */
  237.       
  238.       if(!scr->localinfo.listentries) {
  239.         scr->localinfo.listsize = DEFAULT_LISTSIZE;
  240.         GETMEM(scr->localinfo.list,
  241.                scr->localinfo.listsize*sizeof(struct Identifier *));
  242.       }
  243.       
  244.       /*
  245.        * Have we room for those new local symbols?
  246.        */
  247.       if(firstid + amount >= scr->localinfo.listsize) {
  248.         scr->localinfo.listsize = firstid + amount+1; /* OLD += DEFAULT_LISTSIZE; */
  249.         GETMEM(temp,
  250.                scr->localinfo.listsize*sizeof(struct Identifier *));
  251.         memcpy(temp, scr->localinfo.list, 
  252.                scr->localinfo.listentries * sizeof(struct Identifier *) );
  253.         FREE(scr->localinfo.list);
  254.         scr->localinfo.list = temp;
  255.       }
  256.  
  257.       
  258.       while(amount--) {
  259.         CALL(ReturnVariable(scr, 
  260.                             &scr->localinfo.list [ firstid ],
  261.                             flags));
  262.         CALL(AddToList(scr, scr->localinfo.list [ firstid ], &scr->locals));
  263.         if(++firstid > scr->localinfo.listentries)
  264.           scr->localinfo.listentries = firstid;
  265.       }
  266.     }
  267.     else {
  268.       /* add to the global list */
  269.  
  270.       if(!scr->globalinfo->listentries) {
  271.         scr->globalinfo->listsize = DEFAULT_LISTSIZE;
  272.         GETMEMA(scr->globalinfo->list,
  273.                scr->globalinfo->listsize*sizeof(struct Identifier *));
  274.       }
  275.       
  276.       /* this is a certain amount of local symbols */
  277.       if(firstid + amount >= scr->globalinfo->listsize) {
  278.         scr->globalinfo->listsize = firstid + amount + 1;
  279.         GETMEMA(temp,
  280.                scr->globalinfo->listsize*sizeof(struct Identifier *));
  281.         memcpy(temp, scr->globalinfo->list, 
  282.                scr->globalinfo->listentries * sizeof(struct Identifier *) );
  283.         FREEA(scr->globalinfo->list);
  284.         scr->globalinfo->list = temp;
  285.       }
  286.       
  287.       while(amount--) {
  288.         CALL(ReturnVariable(scr, 
  289.                             &scr->globalinfo->list [ firstid ],
  290.                             flags));
  291.         CALL(AddToList(scr, scr->globalinfo->list [ firstid ],
  292.                        &scr->globals));
  293.         if(++firstid > scr->globalinfo->listentries)
  294.           scr->globalinfo->listentries = firstid;
  295.       }
  296.     }
  297.   }
  298.   else {
  299.     CALL(ReturnVariable(scr, &ident, flags));
  300.     ident->name = scr->prog->program + scr->prog->index + firstid +
  301.       sizeof(long); /* skip the hash for now */
  302.     CALL(AddVar(scr, ident, &scr->globals));
  303.     scr->text += sizeof(long)*2;
  304.   }
  305.   
  306.   return FPL_OK;
  307. }
  308.  
  309. ReturnCode REGARGS
  310. CmpStringExpr(struct Expr *val,        /* original string -> new */
  311.          struct Data *scr)        /* standard */
  312. {
  313.   ReturnCode ret;
  314.   struct fplStr *whole;
  315.  
  316.   Pass2 code=GETSHORT;
  317.   
  318.   if(PASS2_STRING_APPEND == code ||
  319.      PASS2_PLUS == code) {
  320.  
  321.     GETMEM(whole, sizeof(struct fplStr));
  322.     memset(whole, 0, sizeof(struct fplStr));
  323.     
  324.     /* put string in new string variable */
  325.     CALL(StrAssign(val->val.str, scr, &whole,
  326.                    TRUE)); /* TRUE == append */
  327.     
  328.     do {
  329.       
  330.       P_SHORT; /* pass the add instruction */
  331.       CALL(CmpExpr(val, scr, CON_STRING));
  332.  
  333.       /* append string to that new variable */
  334.       CALL(StrAssign(val->val.str, scr, &whole, TRUE));
  335.       
  336.       if(!(val->flags&FPL_NOFREE) && val->val.str)
  337.     FREE(val->val.str);
  338.  
  339.       code= GETSHORT;
  340.       
  341.     } while(PASS2_STRING_APPEND == code ||
  342.             PASS2_PLUS == code );
  343.       
  344.     val->val.str = whole; /* get the string info! */
  345.     val->flags&=~FPL_NOFREE; /* free this, yes! */
  346.   }
  347.   return FPL_OK;
  348. }
  349.  
  350.  
  351. /*
  352.  * Let's fix this bloody assign, and leave the return code in the
  353.  * (struct Expr *) we get!
  354.  */
  355.  
  356.  
  357. ReturnCode REGARGS
  358. AssignVar(struct Data *scr,
  359.           struct Expr *val,
  360.           struct Identifier *ident,
  361.           long type) /* assign type */
  362. {
  363.   ReturnCode ret;
  364.   long pos=0;
  365.   Pass2 code;
  366.   long dim;
  367.   long dimensions=0;
  368.   long *array=NULL;
  369.   char multi=FALSE;
  370.  
  371.   long value;
  372.   uchar *valuep;
  373.   struct fplStr **string=NULL;
  374.  
  375.   scr->text += sizeof(long)*2; /* pass the information data */
  376.   code = GETSHORT;
  377.   if( PASS2_OPEN_BRACKET == code && ident->data.variable.num ) {
  378.     /*
  379.      * This is an array member assign!
  380.      */
  381.     GETMEM(array, ident->data.variable.num*sizeof(long));
  382.     do {
  383.       P_SHORT; /* pass open bracket */
  384.       CALL(CmpExpr(val, scr, CON_GROUNDLVL|CON_NUM));
  385.       P_SHORT; /* pass close bracket */
  386.       if(val->val.val < 0)
  387.         /* illegal result of the expression */
  388.         return FPLERR_ILLEGAL_ARRAY;
  389.       array[ dimensions++ ] = val->val.val;
  390.       if(dimensions == ident->data.variable.num )
  391.         /* we've hit the roof! */
  392.         break;
  393.     } while(PASS2_OPEN_BRACKET == GETSHORT);
  394.     code = GETSHORT;
  395.   }
  396.   if(PASS2_OPEN_BRACE == code) {
  397.     P_SHORT;
  398.     dim=1; /* first dimension assign */
  399.     multi=TRUE;
  400.     if(!array) {
  401.       /* then get an array! */
  402.       GETMEM(array, ident->data.variable.num * sizeof(long));
  403.       /* and clear it */
  404.       memset(array, 0, ident->data.variable.num * sizeof(long) );
  405.       /* set number of dimensions */
  406.       dimensions = ident->data.variable.num;
  407.     }
  408.   }
  409.   do {
  410.     if(multi) {
  411.       code = GETSHORT;
  412.       switch(code) {
  413.       case PASS2_OPEN_BRACE:
  414.         ++dim;
  415.         P_SHORT;
  416.         continue;
  417.       case PASS2_CLOSE_BRACE:
  418.         --dim;
  419.         P_SHORT;
  420.         array[dim]=0; /* start over at zero at this dimension */
  421.         continue;
  422.       case PASS2_COMMA:
  423.         array[ dim-1 ] ++;
  424.         P_SHORT;
  425.         continue;
  426.       }
  427.     }
  428.     if(array) {
  429.       pos = ArrayNum(dimensions, ident->data.variable.num,
  430.                      array, ident->data.variable.dims);
  431.       if( 0 > pos) {
  432.         scr->buf[0]=0;
  433.         return FPLERR_ILLEGAL_ARRAY;
  434.       }
  435.     }
  436.     if(ident->flags&FPL_INT_VARIABLE) {
  437.       CALL(CmpExpr(val, scr, CON_NORMAL));
  438.       CALL(CmpAssign(scr, val->val.val,
  439.                      &ident->data.variable.var.val32[pos],
  440.                      ident->flags, type));
  441.       val->val.val=ident->data.variable.var.val32[pos];
  442.     }
  443.     else {
  444.       /*
  445.        * String assigns
  446.        */
  447.       if(!multi &&
  448.          PASS2_OPEN_BRACKET == code) {
  449.         /* single character assign! */
  450.         P_SHORT; /* pass open bracket */
  451.         CALL(CmpExpr(val, scr, CON_GROUNDLVL|CON_NUM));
  452.         P_SHORT; /* pass close bracket */
  453.         if(!ident->data.variable.var.str[ pos ] ||
  454.            !ident->data.variable.var.str[ pos ] ->len)
  455.           /* no-length-string */
  456.           return FPLERR_STRING_INDEX;
  457.         if(val->val.val >= ident->data.variable.var.str[ pos ]->len)
  458.           /* force to zero! */
  459.           val->val.val=0;
  460.         valuep = (uchar *)&ident->data.variable.var.str[ pos ]->string[val->val.val];
  461.         value = *(uchar *)valuep;
  462.         CALL(CmpExpr(val, scr, CON_NORMAL));
  463.         CALL(CmpAssign(scr, val->val.val, &value, FPL_CHAR_VARIABLE, type));
  464.         val->val.val= *valuep = (uchar)value; /* assign it for real! */
  465.       }
  466.       else {
  467.         CALL( CmpExpr(val, scr, CON_STRING) );
  468.         CALL( CmpStringExpr(val, scr) ); /* check for more */
  469.     
  470.         string = &ident->data.variable.var.str[pos];
  471.         if((CHAR_PLUS != type) && val->flags&FPL_NOFREE) {
  472.           /*
  473.            * Only do this this is not an append action _and_
  474.            * we can't free this string (== someone else is
  475.            * taking care of this string!)
  476.            */
  477.           if(*string) {
  478.             FREE_KIND(*string); /* free old string */
  479.           }
  480.           if(val->val.str) {
  481.             /* duplicate string */
  482.             STRFPLDUP((*string), val->val.str);
  483.           }
  484.           else
  485.             *string=NULL;
  486.         }
  487.     else {
  488.           CALL(StrAssign(val->val.str, scr, string,
  489.                          CHAR_PLUS == type) ); /* TRUE or FALSE if append */
  490.         }
  491.         if(*string && MALLOC_STATIC == TypeMem(ident) )
  492.           SwapMem(scr, *string, MALLOC_STATIC);
  493.        
  494.         if((CHAR_PLUS == type) && !(val->flags&FPL_NOFREE) && val->val.str)
  495.           /* Only do this if appending! */
  496.           FREE(val->val.str);
  497.       }
  498.     }
  499.     if(!multi)
  500.       break;
  501.       
  502.     P_SHORT; /* pass END_OF_EXPR */
  503.  
  504. #if 0
  505.     code = GETSHORT;
  506.     
  507.     P_SHORT; /* pass COMMA or CLOSE_BRACE */
  508. #endif
  509.  
  510.   } while( dim > 0 ); /* repeat while we still assign first or more dims */
  511.  
  512.   if(string) {
  513.     val->val.str=*string;
  514.     val->flags=FPL_STRING|FPL_NOFREE;
  515.   }
  516.   else
  517.     val->flags=0;
  518.  
  519.   if(array)
  520.     FREE(array); /* free temporary space */
  521.   return FPL_OK;
  522. }
  523.  
  524. static ReturnCode ReferToThis(struct Identifier **ident)
  525. {
  526.   if(!((*ident)->flags&FPL_REFERENCE))
  527.     return FPLERR_ILLEGAL_REFERENCE; /* referenced a non-reference! */
  528.   if(!(*ident)->data.variable.ref)
  529.     return FPLERR_ILLEGAL_REFERENCE; /* illegal reference! */
  530.   *ident = (*ident)->data.variable.ref; /* use the "actual" variable! */
  531.   return FPL_OK;
  532. }
  533.  
  534. ReturnCode REGARGS
  535. CmpExpr(struct Expr *val, /* return value struct pointer */
  536.         struct Data *scr, /* everything */
  537.         long control)     /* ESPECIALLLY DEFINED */
  538. {
  539.   struct Expr *expr, *basexpr;
  540.   ReturnCode ret;
  541.   struct Identifier *ident; /* general purpose struct identifier pointer */
  542.   long num;
  543.   uchar *pnt;
  544.   Pass2 code;
  545.   uchar contentsof=FALSE;
  546. #if defined(AMIGA) && defined(SHARED)
  547.   if(ret=CheckStack(scr, scr->stack_limit, scr->stack_margin)) {
  548.     if(ret==1)
  549.       return(FPLERR_OUT_OF_MEMORY);
  550.     else
  551.       return(FPLERR_OUT_OF_STACK);
  552.   }
  553. #endif
  554.  
  555.   GETMEM(expr, sizeof(struct Expr));
  556.   memset(expr, 0, sizeof(struct Expr));
  557.   basexpr=expr;
  558.  
  559.   do {
  560.     code = GETSHORT;
  561.     P_SHORT; /* pass the instruction code */
  562.  
  563.     switch(code) {
  564.       case PASS2_LINE_NUMBER:
  565.         scr->virprg = GETLONG;
  566.         P_LONG;
  567.         continue;
  568.       /*
  569.        * Three cases of simple references.
  570.        */
  571.       case PASS2_REF_LOCAL_SYMBOL:
  572.         ident = scr->localinfo.list[ GETLONG ];
  573.         P_LONG;
  574.         if(contentsof) {
  575.           CALL(ReferToThis(&ident));
  576.           contentsof=FALSE;
  577.         }
  578.         CALL(FixVariable(scr, ident, control, expr));
  579.         CALL(NewMember(scr, &expr));
  580.         break;
  581.       case PASS2_REF_GLOBAL_SYMBOL:
  582.         ident = scr->globalinfo->list[ GETLONG ];
  583.         P_LONG;
  584.         if(contentsof) {
  585.           CALL(ReferToThis(&ident));
  586.           contentsof=FALSE;
  587.         }
  588.         CALL(FixVariable(scr, ident, control, expr));
  589.         CALL(NewMember(scr, &expr));
  590.         break;
  591.       case PASS2_REF_EXPORT_SYMBOL:
  592.         pnt = (uchar *) &scr->prog->program[ GETLONG +
  593.           scr->prog->index +
  594.             sizeof(long)];  /* skip hash for now */
  595.         CALL(GetIdentifier(scr, pnt, &ident));
  596.         P_LONG;
  597.         if(contentsof) {
  598.           CALL(ReferToThis(&ident));
  599.           contentsof=FALSE;
  600.         }
  601.         CALL(FixVariable(scr, ident, control, expr));
  602.         CALL(NewMember(scr, &expr));
  603.         break;
  604.  
  605.       /*
  606.        * Three cases of assigns.
  607.        */
  608.       case PASS2_ASSIGN_LOCAL_SYMBOL:
  609.         /* (varnum) (assign type);... local list */
  610.         ident = scr->localinfo.list[ GETLONG ];
  611.         if(contentsof) {
  612.           CALL(ReferToThis(&ident));
  613.           contentsof=FALSE;
  614.         }
  615.         CALL(AssignVar(scr, expr, ident, *(long *)(scr->text+sizeof(long)) ));
  616.         CALL(NewMember(scr, &expr));
  617.         P_SHORT; /* pass the end of expr code */
  618.         break;
  619.       case PASS2_ASSIGN_GLOBAL_SYMBOL:
  620.         /* (varnum) (assign type);... global list */
  621.         ident = scr->globalinfo->list[ GETLONG ];
  622.         if(contentsof) {
  623.           CALL(ReferToThis(&ident));
  624.           contentsof=FALSE;
  625.         }
  626.         CALL(AssignVar(scr, expr, ident, *(long *)(scr->text+sizeof(long)) ));
  627.         CALL(NewMember(scr, &expr));
  628.         P_SHORT; /* pass the end of expr code */
  629.         break;
  630.       case PASS2_ASSIGN_EXPORT_SYMBOL:
  631.         /* (assigntyp) (string-offset) */
  632.         num = GETLONG; /* assign type */
  633.         pnt = (uchar *)
  634.           &scr->prog->program[ (*(long *)(scr->text+ sizeof(long)))+
  635.                                scr->prog->index +
  636.                                sizeof(long) ];  /* skip hash for now */
  637.         CALL(GetIdentifier(scr, pnt, &ident));
  638.         if(contentsof) {
  639.           CALL(ReferToThis(&ident));
  640.           contentsof=FALSE;
  641.         }
  642.         CALL(AssignVar(scr, expr, ident, num ));
  643.         CALL(NewMember(scr, &expr));
  644.         P_SHORT; /* pass the end of expr code */
  645.         break;
  646.  
  647.       case PASS2_CALL_LOCAL_FUNCTION:
  648.       case PASS2_CALL_INTERNAL_FUNCTION:
  649.       case PASS2_CALL_EXPORT_FUNCTION:
  650.         {
  651.           struct Expr **exprp;
  652.           GETMEM(exprp, sizeof(struct Expr *));
  653.           *exprp = expr;
  654.           CALL(FixFunction(scr, exprp, val, code, control));
  655.           expr = *exprp;
  656.           FREE(exprp);
  657.         }
  658.         break;
  659.  
  660.       case PASS2_CONTENTSOF:
  661.         /*
  662.          * This is the 'contents of' operator!
  663.          */
  664.         contentsof=TRUE;
  665.         break;
  666.  
  667.       case PASS2_NUM_CONSTANT:
  668.         expr->val.val=GETLONG;
  669.         P_LONG;
  670.         CALL(NewMember(scr, &expr));
  671.         break;
  672.  
  673.       case PASS2_STRING_CONSTANT: /* OFFSET to <length> <string> */
  674.         pnt = GETLONG + scr->prog->index + scr->prog->program;
  675.         num = *(long *)pnt;
  676.         GETMEM(expr->val.str, sizeof(struct fplStr)+ num);
  677.         expr->val.str->alloc = expr->val.str->len = num;
  678.         memcpy(expr->val.str->string,
  679.                pnt+sizeof(long), num + 1); /* copy the zero termination too */
  680.         expr->flags=FPL_STRING;
  681.         P_LONG; /* pass the string offset */
  682.         CALL(CmpStringExpr(expr, scr));
  683.         break;
  684.         
  685.       case PASS2_OPEN_PAREN:
  686.         CALL(CmpExpr(val, scr, CON_GROUNDLVL|CON_NUM));
  687.         expr->val.val=val->val.val;
  688.         CALL(NewMember(scr, &expr));
  689.         P_SHORT; /* pass close paren */
  690.         break;
  691.  
  692.       case PASS2_NOTOPERATOR:
  693.         CALL(AddUnary(scr, expr, OP_NOT));
  694.         break;
  695.  
  696.       case PASS2_ONCECOMPLEMENT:
  697.         CALL(AddUnary(scr, expr, OP_COMPL));
  698.         break;
  699.  
  700.       case PASS2_PREINC:
  701.         CALL(AddUnary(scr, expr, OP_PREINC));
  702.         break;
  703.  
  704.       case PASS2_PREDEC:
  705.         CALL(AddUnary(scr, expr, OP_PREDEC));
  706.         break;
  707.  
  708.       case PASS2_NEGATE:
  709.         CALL(AddUnary(scr, expr, OP_MINUS));
  710.         break;
  711.  
  712.       case PASS2_EQUAL:
  713.         expr->operator=OP_EQUAL;
  714.         break;
  715.       case PASS2_LOGICAND:
  716.         /*
  717.          * This is a logical AND (&&)
  718.          */
  719.  
  720.         /*
  721.          * Get result from everything to the left of this!
  722.          */
  723.         CALL(Calc(scr, val, basexpr));
  724.  
  725.         /*
  726.          * Clean the expression so far.
  727.          */
  728.         Clean(scr, basexpr);    /* erase the list */
  729.  
  730.         /*
  731.          * Start a new list with this result
  732.          */
  733.         GETMEM(expr, sizeof(struct Expr));
  734.         memset(expr, 0, sizeof(struct Expr));
  735.         basexpr=expr;
  736.         expr->val.val = val->val.val;
  737.  
  738.         if(!expr->val.val) {
  739.           /*
  740.            * In this case, its like in the 'a && b' expression and 'a'
  741.            * equals 0. Then we should skip the 'b' expression.
  742.            */
  743.           scr->text =
  744.             &scr->prog->program [ scr->prog->index + GETLONG ];
  745.         }
  746.         else
  747.           P_LONG; /* pass index */
  748.         break;
  749.  
  750.       case PASS2_BINARYAND:
  751.         expr->operator=OP_BINAND;
  752.         break;
  753.       case PASS2_LOGICOR:
  754.         /*
  755.          * This is a logical OR operator (||)
  756.          */
  757.  
  758.         /*
  759.          * Get result from everything to the left of this!
  760.          */
  761.         CALL(Calc(scr, val, basexpr));
  762.  
  763.         /*
  764.          * Clean the expression so far.
  765.          */
  766.         Clean(scr, basexpr);    /* erase the list */
  767.  
  768.         /*
  769.          * Start a new list with this result
  770.          */
  771.         GETMEM(expr, sizeof(struct Expr));
  772.         memset(expr, 0, sizeof(struct Expr));
  773.         basexpr=expr;
  774.         expr->val.val = val->val.val;
  775.  
  776.         if(expr->val.val) {
  777.           /*
  778.            * In this case, its like in the 'a || b' expression and 'a'
  779.            * equals 1. Then we should skip the 'b' expression.
  780.            */
  781.           scr->text =
  782.             &scr->prog->program [ scr->prog->index + GETLONG ];
  783.         }
  784.         else
  785.           P_LONG; /* pass index */
  786.         break;
  787.       case PASS2_BINARYOR:
  788.         expr->operator=OP_BINOR;
  789.         break;
  790.       case PASS2_PLUS:
  791.     if(control&CON_STRING) {
  792.           scr->text -= sizeof(short); /* back on the instruction code */
  793.           code = PASS2_END_OF_EXPR; /* force break-out-of-loop */
  794.     }
  795.     else
  796.           expr->operator=OP_PLUS;
  797.         break;
  798.       case PASS2_MINUS:
  799.         expr->operator=OP_MINUS;
  800.         break;
  801.       case PASS2_CONDOPSTART:
  802.         /*
  803.          * This is the first operator in a conditional operator sequence (?)
  804.          */
  805.  
  806.         /*
  807.          * Get result from everything to the left of this!
  808.          */
  809.         CALL(Calc(scr, val, basexpr));
  810.  
  811.         /*
  812.          * Clean the expression so far.
  813.          */
  814.         Clean(scr, basexpr);    /* erase the list */
  815.  
  816.         /*
  817.          * Start a new list with this result
  818.          */
  819.         GETMEM(expr, sizeof(struct Expr));
  820.         memset(expr, 0, sizeof(struct Expr));
  821.         expr->flags = FPL_OPERAND;
  822.         basexpr=expr;
  823.  
  824.         if(val->val.val) {
  825.           /*
  826.            * In this case, its like in the 'a ? b : c' expression and 'a'
  827.            * equals 1. Then we should skip the 'c' expression.
  828.            */
  829.           P_LONG; /* pass index */
  830.           
  831.           CALL(CmpExpr(val, scr, CON_NORMAL));
  832.           /*
  833.            * We're on a LABEL_GOTO right now!
  834.            */
  835.           P_SHORT; /* pass the instruction */
  836.           /* goto the new position */
  837.           scr->text =
  838.             &scr->prog->program [ scr->prog->index + GETLONG ];
  839.         }
  840.         else {
  841.           /*
  842.            * In this case, its like in the 'a ? b : c' expression and 'a'
  843.            * equals 0. Then we should skip the 'b' expression.
  844.            */
  845.            /* goto position */
  846.           scr->text =
  847.             &scr->prog->program [ scr->prog->index + GETLONG ];
  848.           CALL(CmpExpr(val, scr, CON_NORMAL));
  849.         }
  850.         expr->val.val = val->val.val;
  851.         break;
  852.       case PASS2_MULTIPLY:
  853.         expr->operator=OP_MULTIPLY;
  854.         break;
  855.       case PASS2_DIVISION:
  856.         expr->operator=OP_DIVISION;
  857.         break;
  858.       case PASS2_REMAIN:
  859.         expr->operator=OP_REMAIN;
  860.         break;
  861.       case PASS2_XOR:
  862.         expr->operator=OP_BINXOR;
  863.         break;
  864.       case PASS2_LESSEQ:
  865.         expr->operator=OP_LESSEQ;
  866.         break;
  867.       case PASS2_SHIFTLEFT:
  868.         expr->operator=OP_SHIFTL;
  869.         break;
  870.       case PASS2_LESS:
  871.         expr->operator=OP_LESS;
  872.         break;
  873.       case PASS2_GREATEQ:
  874.         expr->operator= OP_GRETEQ;
  875.         break;
  876.       case PASS2_SHIFTRIGHT:
  877.         expr->operator=OP_SHIFTR;
  878.         break;
  879.       case PASS2_GREATER:
  880.         expr->operator=OP_GRET;
  881.         break;
  882.       case PASS2_NOTEQUAL:
  883.         expr->operator=OP_NOTEQ;
  884.         break;
  885.       case PASS2_COMMA:
  886.         if(control&CON_GROUNDLVL) {
  887.           /*
  888.            * Get result from everything to the left of this!
  889.            * For unary operators.
  890.            */
  891.           CALL(Calc(scr, val, basexpr));
  892.           
  893.           Clean(scr, basexpr);
  894.           GETMEM(basexpr, sizeof(struct Expr));
  895.           expr=basexpr;
  896.           expr->val.val=0;
  897.           expr->unary=NULL;
  898.           expr->operator=expr->flags=OP_NOTHING;
  899.           expr->next=NULL;
  900.           break;
  901.         }
  902.         /* FALLS THROUGH */
  903.       /* case PASS2_END_OF_EXPR: */
  904.       default:
  905.         scr->text -= sizeof(short); /* back on the instruction code */
  906.         code = PASS2_END_OF_EXPR; /* force break-out-of-loop */
  907.         break;
  908.     }
  909. #if 0
  910.     if(expr->flags&FPL_STRING && !(control&CON_GROUNDLVL))
  911.       /* get outta string calcs if not on ground level! */
  912.       break;
  913. #endif
  914. #if 0
  915.     if(control&CON_STRING)
  916.       /* get outta string calcs if not on ground level! */
  917.       break;
  918. #endif
  919.   } while(PASS2_END_OF_EXPR != code);
  920.  
  921.   if(!(control&CON_NORETURN)) {
  922.     /*
  923.      * Get result of the current expression.
  924.      */
  925.     CALL(Calc(scr, val, basexpr));
  926.   }
  927.   Clean(scr, basexpr);    /* erase the rest of the list */
  928.   return(FPL_OK);
  929. }
  930.  
  931. ReturnCode REGARGS
  932. GetArrayNum(struct Data *scr,
  933.             struct Expr *expr,
  934.             long *dims,
  935.             struct Identifier *ident)
  936. {
  937.   long *array;
  938.   ReturnCode ret;
  939.   *dims=0;
  940.   /*
  941.    * This is an array reference!
  942.    */
  943.   GETMEM(array, ident->data.variable.num*sizeof(long));
  944.   do {
  945.     P_SHORT; /* pass open bracket */
  946.     CALL(CmpExpr(expr, scr, CON_GROUNDLVL|CON_NUM));
  947.     P_SHORT; /* pass close bracket */
  948.     if(expr->val.val < 0)
  949.       /* illegal result of the expression */
  950.       return FPLERR_ILLEGAL_ARRAY;
  951.     array[ (*dims)++ ] = expr->val.val;
  952.     if(*dims == ident->data.variable.num )
  953.       /* we've hit the roof! */
  954.       break;
  955.   } while(PASS2_OPEN_BRACKET == GETSHORT);
  956.   *dims = ArrayNum(*dims, ident->data.variable.num, array,
  957.                     ident->data.variable.dims);
  958.   if( 0 > *dims)
  959.     return FPLERR_ILLEGAL_ARRAY;
  960.   FREE(array); /* free temporary space */
  961.   
  962.   return FPL_OK;
  963. }
  964.  
  965. ReturnCode REGARGS
  966. FixVariable(struct Data *scr,
  967.             struct Identifier *ident,
  968.             long control,
  969.             struct Expr *expr)
  970. {
  971.   Pass2 code;
  972.   long *array=NULL;
  973.   long dims=0;
  974.   ReturnCode ret;
  975.   
  976.   if(!ident)
  977.     return FPLERR_IDENTIFIER_NOT_FOUND;
  978.  
  979.   code = GETSHORT;
  980.  
  981.   if(PASS2_RESIZE == code) {
  982.     /*
  983.      * Ooops! ;) This is a resize operation and not at all any
  984.      * 'real' variable reference.
  985.      */
  986.     P_SHORT; /* pass resize instruction */
  987.     GETMEM(array, MAX_DIMS*sizeof(long));
  988.     do {
  989.       P_SHORT; /* pass open bracket */
  990.       CALL(CmpExpr(expr, scr, CON_GROUNDLVL|CON_NUM));
  991.       P_SHORT; /* pass close bracket */
  992.       array[ dims++ ] = expr->val.val;
  993.     } while(PASS2_OPEN_BRACKET == GETSHORT);
  994.     CALL(ArrayResize(scr, dims, array, ident));
  995.     FREE(array); /* free temporary space */
  996.     return FPL_OK;
  997.   }
  998.  
  999.   if( PASS2_OPEN_BRACKET == code && ident->data.variable.num ) {
  1000.     /*
  1001.      * This is an array reference!
  1002.      */
  1003.     CALL(GetArrayNum(scr, expr, &dims, ident));
  1004.     code = GETSHORT;
  1005.   }
  1006.  
  1007.   if(ident->flags&FPL_STRING_VARIABLE) {
  1008.     if(PASS2_OPEN_BRACKET == code) {
  1009.       
  1010.       /*
  1011.        * Yet another bracket means this is a single-character access
  1012.        * from a string!
  1013.        */
  1014.        
  1015.       P_SHORT; /* pass open bracket */
  1016.       CALL(CmpExpr(expr, scr, CON_GROUNDLVL|CON_NUM));
  1017.       P_SHORT; /* pass close bracket */
  1018.       if(!ident->data.variable.var.str[ dims ] ||
  1019.          !ident->data.variable.var.str[ dims ] ->len)
  1020.         /* no-length-string */
  1021.         return FPLERR_STRING_INDEX;
  1022.       if(expr->val.val >= ident->data.variable.var.str[ dims ]->len)
  1023.         /* force to zero! */
  1024.         expr->val.val=0;
  1025.  
  1026.       expr->val.val =
  1027.         ident->data.variable.var.str[ dims ]->string[expr->val.val];
  1028.     }
  1029.     else {
  1030.       expr->val.str = ident->data.variable.var.str[ dims ];
  1031.       expr->flags |= FPL_NOFREE; /* don't free this! */
  1032.     }
  1033.   }
  1034.   else {
  1035.     struct Unary *un; /* Unary information struct pointer */
  1036.     long *value = &ident->data.variable.var.val32[ dims ];
  1037.     if(PASS2_POSTINC == code ) {
  1038.       expr->val.val=(*value)++;
  1039.       P_SHORT;
  1040.     }
  1041.     else if(PASS2_POSTDEC == code) {
  1042.       expr->val.val=(*value)--;
  1043.       P_SHORT;
  1044.     }
  1045.     else if(un=expr->unary) {
  1046.       if(un->unary!=OP_PREINC && un->unary!=OP_PREDEC) {
  1047.         expr->val.val=*value;
  1048.       } else {
  1049.         if(ident->flags&FPL_READONLY)
  1050.           return FPLERR_READONLY_VIOLATE;
  1051.         if(un->unary==OP_PREINC)
  1052.           expr->val.val=++(*value);
  1053.         else
  1054.           expr->val.val=--(*value);
  1055.         expr->unary=un->next;
  1056.         FREE(un);
  1057.       }
  1058.     } else
  1059.       expr->val.val=*value;
  1060.   }
  1061.   return FPL_OK;
  1062. }
  1063.  
  1064. ReturnCode REGARGS
  1065. FixFunction(struct Data *scr,
  1066.             struct Expr **exprp,
  1067.             struct Expr *val, /* pass on struct pointer */
  1068.             Pass2 origcode,
  1069.             long control)
  1070. {
  1071.   struct fplArgument *pass; /* struct pointer to send as argument to
  1072.                                the function handler */
  1073.   struct fplArgument *arg2; /* backup pointer */
  1074.   ReturnCode ret;
  1075.  
  1076.   long numofargs; /* amount of arguments used in program */
  1077.   uchar *text; /* pointer to argument format string */
  1078.   uchar *run; /* pointer to new interpret position (local) */
  1079.   uchar *array;
  1080.   struct Expr *expr=*exprp;
  1081.   struct Identifier *ident;
  1082.   struct fplMsg *msg;
  1083.   struct CompiledInfo *comp;
  1084.   uchar *newformat=NULL;
  1085.  
  1086.   uchar hit;
  1087.   expr->flags|=FPL_OPERAND|FPL_ACTION; /* This sure is action...! */
  1088.  
  1089.   GETMEM(pass, sizeof(struct fplArgument));
  1090.  
  1091.   switch(origcode) {
  1092.     case PASS2_CALL_INTERNAL_FUNCTION:
  1093.       pass->name=NULL;
  1094.       pass->ID=GETLONG;
  1095.       break;
  1096.       
  1097.     case PASS2_CALL_LOCAL_FUNCTION:
  1098.       run = &scr->prog->program [ GETLONG + scr->prog->index ];
  1099.       /* 'run' points to the new interpret position */
  1100.       break;
  1101.       
  1102.     case PASS2_CALL_EXPORT_FUNCTION:
  1103.       /* this function is called and recognized by actual name */
  1104.       pass->name =
  1105.         &scr->prog->program [ GETLONG + scr->prog->index + sizeof(long)];
  1106.       break;
  1107.   }
  1108.   
  1109.   P_LONG; /* pass function ID or index or string pointer */
  1110.   
  1111.   P_SHORT; /* pass PASS2_TYPE_OF_ARGUMENTS */
  1112.   
  1113.   text = &scr->prog->program [ GETLONG + scr->prog->index ];
  1114.   /* 'text' points to a string now, that holds the length in the
  1115.      first 32 bits */
  1116.   numofargs = *(long *)text; /* thats the length */
  1117.   text += sizeof(long); /* now point to the actual zero terminated string */
  1118.  
  1119.   P_LONG; /* pass parameter string index */
  1120.   
  1121.   pass->argc=0;
  1122.   pass->key=(void *)scr;
  1123.   pass->format = text; /* already set and known */
  1124.   /*
  1125.    * FIX the other pass members to be set correctly too!
  1126.    */
  1127.   
  1128.   if(numofargs) {
  1129.     uchar a;
  1130.  
  1131.     /* if the function takes arguments */
  1132.  
  1133.     /*
  1134.      * Allocate arrays to use for data storage while parsing
  1135.      * the arguments.
  1136.      */
  1137.  
  1138.     /* allocate an array */
  1139.     GETMEM(pass->argv, sizeof(uchar *)* (numofargs+1) );
  1140.  
  1141.     /* allocate allocate-flag string */
  1142.     GETMEM(array, sizeof(uchar)* (numofargs+1) );
  1143.  
  1144.     /* new format string */
  1145.     GETMEM(newformat, sizeof(uchar)* (numofargs+1) );
  1146.     
  1147.     do {
  1148.       a=*text;
  1149.  
  1150.       switch(a) {
  1151.       case FPL_OPTEXPRARG:
  1152.       case FPL_OPTARG:
  1153.       case FPL_STRARG:
  1154.         CALL(CmpExpr(val, scr, (a==FPL_STRARG?CON_STRING:0) ));
  1155.  
  1156.     if(a==FPL_STRARG || val->flags&FPL_STRING) {
  1157.           CALL(CmpStringExpr(val, scr)); /* get more strings? */
  1158.   
  1159.           if(val->val.str) {
  1160.             /* Set this to TRUE if deallocation is wanted on this
  1161.                string after the function call! */
  1162.             array[pass->argc]=!(val->flags&FPL_NOFREE);
  1163.             /*
  1164.              * Point to the string (that is zero terminated)!
  1165.              */
  1166.             pass->argv[pass->argc]=val->val.str->string;
  1167.           } else {
  1168.             register struct fplStr *string;
  1169.             GETMEM(string, sizeof(struct fplStr));
  1170.             memset(string, 0, sizeof(struct fplStr));
  1171.             pass->argv[pass->argc]=string->string;
  1172.             array [ pass->argc ] = TRUE; /* allocation has been done! */
  1173.           }
  1174.           newformat[pass->argc]=FPL_STRARG;
  1175.     }
  1176.     else {
  1177.           newformat[pass->argc]=FPL_INTARG;
  1178.           pass->argv[pass->argc]=(void *)val->val.val;
  1179.     }
  1180.         pass->argc++;
  1181.         break;
  1182.       case FPL_INTARG:
  1183.         CALL(CmpExpr(val, scr, CON_NUM));
  1184.         newformat[pass->argc]=FPL_INTARG;
  1185.         pass->argv[pass->argc++]=(void *)val->val.val;
  1186.         break;
  1187.       case FPL_OPTVARARG:
  1188.       case FPL_STRVARARG:
  1189.       case FPL_INTVARARG:
  1190.       case FPL_INTARRAYVARARG:
  1191.       case FPL_STRARRAYVARARG:
  1192.         {
  1193.           register ReturnCode ok;
  1194.           register Pass2 code;
  1195.           if(GETSHORT != PASS2_VARIABLE_REFERENCE) {
  1196.             ok = FPLERR_ILLEGAL_REFERENCE;
  1197.           }
  1198.           else {
  1199.             ok = FPL_OK;
  1200.             P_SHORT; /* pass that one */
  1201.           }
  1202.           
  1203.           /* Get identifier */
  1204.           
  1205.           code = GETSHORT;
  1206.           P_SHORT; 
  1207.           switch(code) {
  1208.           case PASS2_REF_LOCAL_SYMBOL:
  1209.             ident = scr->localinfo.list[ GETLONG ];
  1210.             break;
  1211.           case PASS2_REF_GLOBAL_SYMBOL:
  1212.             ident = scr->globalinfo->list[ GETLONG ];
  1213.             break;
  1214.           case PASS2_REF_EXPORT_SYMBOL:
  1215.             {
  1216.               register char *pnt;
  1217.               pnt = (uchar *) &scr->prog->program[ GETLONG +
  1218.                 scr->prog->index + sizeof(long)];  /* skip hash for now */
  1219.               CALL(GetIdentifier(scr, pnt, &ident));
  1220.             }
  1221.             break;
  1222.           }
  1223.           P_LONG; /* pass data */
  1224.  
  1225.           if(ok) {
  1226.             /* missing contensof-operator! */
  1227.             if(ident->flags&FPL_REFERENCE)
  1228.               /* get the referenced variable instead! */
  1229.               ident = ident->data.variable.ref;
  1230.             else
  1231.               return ok; /* no reference! */
  1232.           }
  1233.         }
  1234.  
  1235.         if(FPL_INTARRAYVARARG == a || FPL_STRARRAYVARARG == a) {
  1236.           if(!ident->data.variable.num)
  1237.             return FPLERR_ILLEGAL_REFERENCE;
  1238.         }
  1239.         else if(FPL_OPTVARARG != a && ident->data.variable.num)
  1240.           /* only straight variables! */
  1241.           return FPLERR_ILLEGAL_PARAMETER;
  1242.  
  1243.         if( (ident->flags&FPL_INT_VARIABLE &&
  1244.              (a==FPL_STRVARARG || a == FPL_STRARRAYVARARG)) ||
  1245.            (ident->flags&FPL_STRING_VARIABLE &&
  1246.             (a==FPL_INTVARARG || a == FPL_INTARRAYVARARG))) {
  1247.           return FPLERR_ILLEGAL_VARIABLE;
  1248.         }
  1249.         pass->argv[pass->argc]=(void *)ident;
  1250.         newformat[pass->argc++]=
  1251.       (ident->flags&FPL_STRING?
  1252.      (ident->data.variable.num?FPL_STRARRAYVARARG:FPL_STRVARARG):
  1253.        (ident->data.variable.num?FPL_INTARRAYVARARG: FPL_INTVARARG));
  1254.         break;
  1255.       }
  1256.       P_SHORT; /* pass the COMMA or CLOSE_PAREN */
  1257.     } while (*++text);
  1258.     newformat[pass->argc]=CHAR_ASCII_ZERO;
  1259.     pass->format = newformat;
  1260.   }
  1261.   else
  1262.     P_SHORT; /* pass the closing paren */
  1263.  
  1264.   /*
  1265.    * Call the function!
  1266.    */
  1267.  
  1268.   if(PASS2_CALL_INTERNAL_FUNCTION == origcode) {
  1269.     CALL(functions(pass));
  1270.   }
  1271.   else {
  1272.     /*
  1273.      * Allocate temporary storage for our local symbols.
  1274.      */
  1275.     GETMEM(comp, sizeof(struct CompiledInfo));
  1276.     memcpy(comp, &scr->localinfo, sizeof(struct CompiledInfo)); /* copy */
  1277.     /*
  1278.      * Clear the items to enforce a new allocated list
  1279.      */
  1280.     scr->localinfo.listentries = scr->localinfo.listsize =0;
  1281.       
  1282.     arg2 = scr->arg; /* store the old */
  1283.     scr->arg = pass; /* for compiled functions */
  1284.       
  1285.     text = scr->text; /* store current interpret position */
  1286.       
  1287.     if(PASS2_CALL_LOCAL_FUNCTION == origcode) {
  1288.       char oldret;
  1289.       
  1290.       scr->text = run; /* set interpret point to local function index */
  1291.       /*
  1292.        * Recurse this at the new position.
  1293.        */
  1294.       oldret=scr->strret;
  1295.       scr->strret=control&CON_STRING?1:0; /* should we receive a string? */
  1296.       CALL(Script(scr, val, SCR_BRACE|SCR_FUNCTION, NULL));
  1297.       scr->strret=oldret;
  1298.     }
  1299.     else {
  1300.       /* EXPORTED FUNCTION */
  1301.       ret=GetIdentifier(scr, pass->name, &ident);
  1302.       if(ret) {
  1303.         /* copy the variable name to make a decent error */
  1304.         strcpy(scr->buf, pass->name);
  1305.         return ret;
  1306.       }
  1307.       pass->ID=ident->data.external.ID; /* set ID */
  1308.       CALL(CallFunction(scr, pass, ident));
  1309.     }
  1310.     
  1311.     scr->text = text; /* restore previous execute point */
  1312.     scr->arg = arg2;  /* restore previous argument pointer */
  1313.     
  1314.     /*
  1315.      * Free the previous local variables and get back our old
  1316.      */
  1317.     if(scr->localinfo.listsize) {
  1318.       /* There is an allocated one here */
  1319.       FREE(scr->localinfo.list);
  1320.     }
  1321.     memcpy(&scr->localinfo, comp,
  1322.            sizeof(struct CompiledInfo)); /* copy */
  1323.     FREE(comp);
  1324.   }
  1325.  
  1326.   CALL(GetMessage(scr, FPLMSG_RETURN, &msg));
  1327.   if(control & CON_NUM)
  1328.     hit = FPL_INTARG;
  1329.   else if(control & CON_STRING)
  1330.     hit = FPL_STRARG;
  1331.   else {
  1332.     if(msg) {
  1333.       if(msg->flags&FPLMSG_FLG_INT) {
  1334.         /* There is a return 'int' message! This may well be a
  1335.            function returning int! */
  1336.         hit = FPL_INTARG;
  1337.       }
  1338.       else {
  1339.         /* found string, it returned a 'string' !!! */
  1340.         hit = FPL_STRARG;
  1341.       }
  1342.     }
  1343.     else
  1344.       hit = FPL_INTARG;
  1345.     /* There is no return nor hint! */
  1346.   }
  1347.  
  1348.   switch(hit) {
  1349.     case FPL_STRARG:
  1350.       if(msg && ((msg->flags&FPLMSG_FLG_BITS) != FPLMSG_FLG_STRING))
  1351.         return FPLERR_UNEXPECTED_INT_STATEMENT;
  1352.       if(!msg || !msg->message[0])
  1353.         /* We got a zero length string or no string at all! */
  1354.         expr->val.str=NULL; /* no string! */
  1355.       else
  1356.         /* the copied string! */
  1357.         expr->val.str=(struct fplStr *)msg->message[0];
  1358.       expr->flags=FPL_STRING|FPL_ACTION;
  1359.       break;
  1360.     case FPL_INTARG:
  1361.     default:
  1362.       if(msg && ((msg->flags&FPLMSG_FLG_BITS) != FPLMSG_FLG_INT))
  1363.         return FPLERR_UNEXPECTED_STRING_STATEMENT;
  1364.       /* only if integer! or the function is non-existent */
  1365.       expr->val.val=(msg?(long)msg->message[0]:0);
  1366.       CALL(NewMember(scr, exprp));
  1367.       break;
  1368.   }
  1369.   if(msg)
  1370.     DeleteMessage(scr, msg);
  1371.  
  1372.   while(pass->argc--) {
  1373.     if(pass->format[pass->argc]==FPL_STRARG && array[pass->argc]) {
  1374.       /* free the string if it's been marked to be freed!! */
  1375.       FREE((uchar *)pass->argv[pass->argc]-
  1376.            offsetof(struct fplStr, string));
  1377.     }
  1378.   }
  1379.   if(numofargs) {
  1380.     FREE(pass->argv);
  1381.     FREE(array);
  1382.     FREE(newformat);
  1383.   }
  1384.   FREE(pass);
  1385.   return FPL_OK;
  1386. }
  1387.  
  1388. ReturnCode REGARGS AssignArg(struct Data *scr)
  1389. {
  1390.   long varnum;
  1391.   long argnum;
  1392.   struct Identifier *ident;
  1393.   struct fplVariable *tempvar;
  1394.   
  1395.   varnum = GETLONG;
  1396.   P_LONG;
  1397.   argnum = GETLONG;
  1398.   P_LONG;
  1399.   
  1400.   ident = scr->localinfo.list[ varnum ]; /* the local variable */
  1401.   tempvar=&ident->data.variable;
  1402.   
  1403.   if(ident->flags & FPL_REFERENCE)
  1404.     ident->data.variable.ref = (struct Identifier *)scr->arg->argv[ argnum ];
  1405.   else if(ident->flags & FPL_STRING_VARIABLE) {
  1406.     /* Store string length in variable `len' */
  1407.     register long len=GETSTRLEN(scr->arg->argv[ argnum ]);
  1408.     GETMEM(tempvar->var.str[0], sizeof(struct fplStr)+len);
  1409.     tempvar->var.str[0]->alloc=len;
  1410.  
  1411.     /* We copy the ending zero termination too! */
  1412.     memcpy(tempvar->var.str[0]->string,
  1413.            ((uchar *)scr->arg->argv[ argnum ]),
  1414.            len+1);
  1415.     tempvar->var.str[0]->len=len;
  1416.   }
  1417.   else {
  1418.     /* Integer assign */
  1419.     tempvar->var.val32[0]=(long)scr->arg->argv[ argnum ];
  1420.   }
  1421.   return FPL_OK;
  1422. }
  1423.  
  1424. ReturnCode REGARGS CmpSwitch(struct Data *scr,
  1425.                              struct Expr *val)
  1426. {
  1427.   ReturnCode ret;
  1428.   struct fplStr *string;
  1429.   long value;
  1430.   long index; /* current index information */
  1431.   char wasstring=FALSE;
  1432.   char jump=FALSE;
  1433.  
  1434.   /* Get expression, string or int, static or dynamic! */
  1435.   CALL(CmpExpr(val, scr, CON_NORMAL));
  1436.   if(val->flags&FPL_STRING) {
  1437.     /* string statement! */
  1438.     string = val->val.str;
  1439.     wasstring=TRUE;
  1440.   }
  1441.   else {
  1442.     /* integer expression */
  1443.     value = val->val.val;
  1444.   }
  1445.   P_SHORT; /* pass the END_OF_EXPR mark */
  1446.   do {
  1447.     P_SHORT; /* pass the CASE mark */
  1448.     index = GETLONG;
  1449.     P_LONG;  /* pass the index */
  1450.   
  1451.     /* Get expression, string or int! */
  1452.     CALL(CmpExpr(val, scr, wasstring?CON_STRING:CON_NUM));
  1453.     if(wasstring) {
  1454.       /*
  1455.        * String comparison:
  1456.        */
  1457.       value = val->val.str?val->val.str->len:0; /* get length */
  1458.   
  1459.       if(value == (string?string->len:0)) { /* compare lengts */
  1460.         if(value) {
  1461.           if(!memcmp(val->val.str->string, string->string, value)) {
  1462.             /* match! */
  1463.             jump=TRUE;
  1464.           }
  1465.         } else
  1466.           jump=TRUE;
  1467.       }
  1468.       if(!val->flags&FPL_NOFREE)
  1469.         FREE(val->val.str);
  1470.     }
  1471.     else {
  1472.       /*
  1473.        * Integer comparison:
  1474.        */
  1475.       if(val->val.val == value)
  1476.         jump = TRUE; /* match */
  1477.     }
  1478.     if(jump) {
  1479.       /* goto index */
  1480.       scr->text = &scr->prog->program[scr->prog->index + index];
  1481.       break; /* we're done! */
  1482.     }
  1483.     P_SHORT; /* pass the END_OF_EXPR */
  1484.   } while(PASS2_CASE == GETSHORT);
  1485.   
  1486.   return FPL_OK;
  1487. }
  1488.  
  1489. ReturnCode REGARGS CmpBreak(struct Data *scr,
  1490.                             struct Expr *val)
  1491. {
  1492.   ReturnCode ret;
  1493.  
  1494.   /* Get integer expression */
  1495.   CALL(CmpExpr(val, scr, CON_NUM));
  1496.   
  1497.   P_SHORT; /* pass END_OF_EXPR */
  1498.   
  1499.   if(val->val.val<=0)
  1500.     return FPLERR_ILLEGAL_BREAK;
  1501.     
  1502.   while(--val->val.val && PASS2_LABEL_GOTO == GETSHORT)
  1503.     scr->text += sizeof(short)+sizeof(long);
  1504.  
  1505.   if(PASS2_END_OF_EXPR == GETSHORT) {
  1506.     P_SHORT; /* just pass it and act cool! */
  1507.   }
  1508.   return FPL_OK; /* leave this standing on the goto! */
  1509. }
  1510.